package com.koron.common.core.util;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.koron.common.core.business.common.entity.TOrderNoMax;
import com.koron.common.core.business.common.service.TOrderNoMaxService;
import com.koron.common.core.business.datadict.bean.po.SysDataDict;
import com.koron.common.core.business.datadict.bean.po.SysDataDictDetail;
import com.koron.common.core.business.datadict.mapper.SysDataDictDetailMapper;
import com.koron.common.core.business.datadict.mapper.SysDataDictMapper;
import com.koron.common.core.config.ThreadLocalContext;
import lombok.extern.slf4j.Slf4j;
import org.koron.ebs.mybatis.ADOConnection;
import org.koron.ebs.mybatis.SessionFactory;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author mwangli
 */
@Slf4j
public class CodeTools {
    private static final char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();

    private static final TOrderNoMaxService tOrderNoMaxService = SpringUtils.getBean(TOrderNoMaxService.class);
    private static Snowflake snowflake = IdUtil.getSnowflake();

    /**
     * 组建流水号
     * 参考main方法
     *
     * @param key        联合主键，自己组合
     * @param dateFormat 日期格式化
     * @return TOrderNoMax对象
     */
    public static TOrderNoMax getNoMax(String key, String dateFormat) {
        return tOrderNoMaxService.getByKey(key, dateFormat);
    }

    /**
     * 生成编码：前缀+日期+序列号
     * exp
     * input: getCodeNo("QXGD","yyyyMM",4)
     * output: QXGD2021010001
     *
     * @param prefix     前缀
     * @param dateFormat 日期格式
     * @param length     长度
     * @return 编码
     */
    public static String getCodeNo(String prefix, String dateFormat, Integer length) {
        TOrderNoMax tOrderNoMax = getNoMax(prefix, dateFormat);
        return prefix + tOrderNoMax.getDate() + String.format("%0" + length + "d", tOrderNoMax.getMaxValue());
    }


    /**
     * 生成编码，租户之间独立
     */
    public static String getCurrAppCodeNo(String prefix, String dateFormat, Integer length) {
        String key = ThreadLocalContext.get().getAppId() + prefix;
        TOrderNoMax tOrderNoMax = getNoMax(key, dateFormat);
        return prefix + tOrderNoMax.getDate() + String.format("%0" + length + "d", tOrderNoMax.getMaxValue());
    }

    /**
     * 生成编码，租户之间独立(无日期)
     */
    public static String getCurrAppCodeNoWithNoDate(String prefix, String dateFormat, Integer length) {
        String key = ThreadLocalContext.get().getAppId() + prefix;
        TOrderNoMax tOrderNoMax = getNoMax(key, dateFormat);
        return prefix + String.format("%0" + length + "d", tOrderNoMax.getMaxValue());
    }


    /**
     * 自定义生成编号，租户之间独立
     * 案例：xxx租户[时间]分包xxx号
     */
    public static String getCurrAppNameCodeNo(String format, String dateFormat, Integer length) {
        String key = ThreadLocalContext.get().getAppName();
        TOrderNoMax tOrderNoMax = getNoMax(key, dateFormat);
        return String.format(format, key, tOrderNoMax.getDate(), String.format("%0" + length + "d", tOrderNoMax.getMaxValue()));
    }

    /**
     * 生成编码，默认日期格式为yyyyMMdd
     *
     * @param prefix 前缀
     * @param length 长度
     * @return 编码
     */
    public static String getCodeNo(String prefix, Integer length) {
        return getCodeNo(prefix, null, length);
    }

    /**
     * // 随机32位长度的字符串
     * 改成使用雪花算法
     *
     * @return 生成的字符串
     */
    public static String getCode32() {
        // 使用雪花算法
        return snowflake.nextIdStr();
    }

    /**
     * 随机64位长度的字符串.
     * 经测试笔记本上生成200000次字符串耗时1560秒。
     *
     * @return 生成的字符串
     */
    public static String getCode64() {
        StringBuilder sb = new StringBuilder(getCode32());
        Random r = new Random();
        int charSize = chars.length;
        for (int i = 0; i < 32; i++) {
            sb.append(chars[r.nextInt(charSize)]);
        }
        return sb.toString();
    }

    /**
     * 用来拼接字符串.
     * 字符串值为null或空字符串时直接忽略
     *
     * @param delimiter 分隔符
     * @param s         需要拼接的字符串
     * @return
     */
    public static String join(String delimiter, CharSequence... s) {
        Objects.requireNonNull(s);
        Objects.requireNonNull(delimiter);
        CharSequence[] target = new CharSequence[s.length];
        //NULL值的次数
        int times = 0;
        for (int i = 0; i < s.length; i++) {
            if (s[i] != null && s[i].length() != 0) {
                target[i - times] = s[i];
            } else {
                times++;
            }
        }
        return String.join(delimiter, Arrays.copyOf(target, target.length - times));
    }


    /**
     * 获取数据字典
     * @param classifyId    字典组
     * @param code          字典code
     * @return
     */
    public static Map<String, String> getDictByClassCode(String classifyId, String code){
        return ADOConnection.runTask("_default", factory-> {
            try {
                SysDataDictMapper sysDataDictMapper = factory.getMapper(SysDataDictMapper.class);
                SysDataDict sysDataDict = sysDataDictMapper.getByClassifyIdAndCode(classifyId, code);
                List<SysDataDictDetail> byDictionary = factory.getMapper(SysDataDictDetailMapper.class).getByDictionary(sysDataDict.getId());
                if(StringUtils.isNotEmpty(byDictionary)){
                    return byDictionary.stream().collect(Collectors.toMap(SysDataDictDetail::getKey, SysDataDictDetail::getValue));
                }
                return new HashMap<>();
            } catch (Exception e) {
                log.error(e.getMessage(),e);
                return new HashMap<>();
            }
        },Map.class);
    }

    /**
     * 获取数据字典
     * @param classifyId    字典组
     * @param code          字典code
     * @return
     */
    public static List<SysDataDictDetail> getDictSortByClassCode(String classifyId, String code){
        return ADOConnection.runTask("_default", factory-> {
            try{
                SysDataDictMapper sysDataDictMapper = factory.getMapper(SysDataDictMapper.class);
                SysDataDict sysDataDict = sysDataDictMapper.getByClassifyIdAndCode(classifyId, code);
                List<SysDataDictDetail> byDictionary = factory.getMapper(SysDataDictDetailMapper.class).getByDictionary(sysDataDict.getId());
                if(StringUtils.isNotEmpty(byDictionary)){
                    return byDictionary;
                }
                return new ArrayList<>();
            } catch (Exception e) {
                log.error(e.getMessage(),e);
            }
            return new ArrayList<>();
        },List.class);
    }
}
